package com.swsc.xapp.offline;

import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.swsc.xapp.activity.mainActivity.MainActivity;
import com.swsc.xapp.model.RestResp;
import com.swsc.xapp.utils.ConstantUils;
import com.swsc.xapp.utils.ContextUtils;
import com.swsc.xapp.utils.FileUtils;
import com.swsc.xapp.utils.GsonUtils;
import com.swsc.xapp.utils.JacksonUtils;
import com.swsc.xapp.utils.JsonUtils;
import com.swsc.xapp.utils.NativeJSUtils;
import com.swsc.xapp.utils.OkHttpUtils;
import com.swsc.xapp.utils.ToastUtils;
import com.swsc.xapp.utils.httpUtil.HttpRequestUtils;
import com.swsc.xapp.xroom.AppDatabase;
import com.swsc.xapp.xroom.CorporationDO;
import com.swsc.xapp.xroom.CorporationService;
import com.swsc.xapp.xroom.DefectDO;
import com.swsc.xapp.xroom.DefectDao;
import com.swsc.xapp.xroom.DefectService;
import com.swsc.xapp.xroom.InfraredImageDO;
import com.swsc.xapp.xroom.InfraredImageService;
import com.swsc.xapp.xroom.PvDeviceInfoDO;
import com.swsc.xapp.xroom.PvDeviceInfoService;
import com.google.gson.reflect.TypeToken;


import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Set;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class DownloadTask extends AsyncTask<String, Integer, Integer> {

    public static final int TYPE_SUCCESS = 0;
    public static final int TYPE_FAILED = 1;
    public static final int TYPE_PAUSED = 2;
    public static final int TYPE_CANCELED = 3;

    private DownloadListener listener;

    private boolean isCanceled = false;

    private boolean isPaused = false;

    private int lastProgress;

    public DownloadTask(DownloadListener listener) {
        this.listener = listener;
    }

    @Override
    protected Integer doInBackground(String... params) {
//        String downloadUrl = params[0];
        // 909901003
        String organNo = params[0];
        if(null == organNo){
            Toast.makeText(ContextUtils.getCurApplication(), "未指定电站", Toast.LENGTH_SHORT).show();
            return TYPE_FAILED;
        }
        String patrolTimeStr = params[1];
        String offlineImageSet = params[2];
        String offlineTiles = params[3];
//        return downloadFile(downloadUrl);
        // 复制空白瓦片图
        FileUtils.copyFileFromAsset("blank_tile.png", ConstantUils.DIR_TILE);
        return offline(Integer.parseInt(organNo),
                patrolTimeStr,
                TextUtils.isEmpty(offlineImageSet) ? null : Boolean.parseBoolean(offlineImageSet),
                TextUtils.isEmpty(offlineTiles) ? null : Boolean.parseBoolean(offlineTiles));
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        int progress = values[0];
        if (progress > lastProgress) {
            listener.onProgress(progress);
            lastProgress = progress;
        }
    }

    @Override
    protected void onPostExecute(Integer integer) {
        switch (integer) {
            case TYPE_SUCCESS:
                listener.onSuccess();
                break;
            case TYPE_FAILED:
                listener.onFailed();
                break;
            case TYPE_PAUSED:
                listener.onPaused();
                break;
            case TYPE_CANCELED:
                listener.onCanceled();
                break;
            default:
                break;
        }
    }

    public void pauseDownload() {
        isPaused = true;
    }

    public void cancelDownload() {
        isCanceled = true;
    }

    private long getContentLength(String downloadUrl) throws IOException {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(downloadUrl)
                .build();
        Response response = client.newCall(request).execute();
        if (response != null && response.isSuccessful()) {
            long contentLength = response.body().contentLength();
            response.body().close();
            return contentLength;
        }
        return 0;
    }

    private Integer downloadFaultImg(String downloadUrl, int progress) {
        String newFileName = downloadUrl.split("/swsc/dfs/")[1];
        return downloadFile(downloadUrl, newFileName, progress);
    }

    private Integer downloadTileImg(String downloadUrl, int progress) {
        String newFileName = downloadUrl.split("/swsc/tiles/")[1];
        return downloadFile(downloadUrl, "tile/" + newFileName, progress);
    }

    private Integer downloadFile(String downloadUrl, String newFileName, final int progress) {
        String fileName = (null == newFileName || "".equals(newFileName.trim())) ? downloadUrl.substring(downloadUrl.lastIndexOf("/")) : newFileName;
        InputStream is = null;
        RandomAccessFile savedFile = null;
        File file = new File(NativeJSUtils.BASE_DIR + fileName);
        NativeJSUtils.checkFileParentDir(file);
        //记录已经下载的文件长度
        long downloadedLength = 0;
        if (file.exists()) {
            downloadedLength = file.length();
        }
        try {

//            String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();

            long contentLength = getContentLength(downloadUrl);
            if (contentLength == 0) {
                return TYPE_FAILED;
            } else if (contentLength == downloadedLength) {
                //已下载字节与总文件字节相等 说明已经下载完成
                return TYPE_SUCCESS;
            }
//            android.util.Log.i("***DOWNLOAD***", "===>" + downloadUrl);
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    //断点下载，指定从那个字节下载
                    .addHeader("RANGE", "bytes=" + downloadedLength + "-")
                    .url(downloadUrl)
                    .build();
            Response response = client.newCall(request).execute();
            if (response != null) {
                is = response.body().byteStream();
                savedFile = new RandomAccessFile(file, "rw");
                savedFile.seek(downloadedLength);//跳过已经下载好的字节
                byte[] b = new byte[1024];
                int total = 0;
                int len;
                while ((len = is.read(b)) != -1) {
                    if (isCanceled) {
                        return TYPE_CANCELED;
                    } else if (isPaused) {
                        return TYPE_PAUSED;
                    } else {
                        total += len;
                        savedFile.write(b, 0, len);
                        //计算已经下载的百分比
                        if (progress < 0) {
                            int localProgress = (int) ((total + downloadedLength) * 100 / contentLength);
                            publishProgress(localProgress);
                        }
                    }
                }
                response.body().close();
                return TYPE_SUCCESS;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (savedFile != null) {
                    savedFile.close();
                }
                if (isCanceled && file != null) {
                    file.delete();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return TYPE_FAILED;
    }

    private Integer offline(Integer organNo, String patrolTimeStr, Boolean offlineImageSet, Boolean offlineTiles) {
        if (null == organNo) {
            return TYPE_FAILED;
        }
        JSONObject golbalUrlObj = NativeJSUtils.readCacheGlobalUrl();
        if (null == golbalUrlObj) {
            return TYPE_FAILED;
        }
        JSONObject userInfo = NativeJSUtils.readCacheUserInfo();
        if (null == userInfo) {
            return TYPE_FAILED;
        }
        Long userNo = userInfo.getLong("userNo");
        if (null == userNo) {
            return TYPE_FAILED;
        }
        String apiUrl = golbalUrlObj.getString(ConstantUils.CK_GLOBAL_API_URL);
        String fileUrl = golbalUrlObj.getString(ConstantUils.CK_GLOBAL_FILE_URL);
        String tileUrl = golbalUrlObj.getString(ConstantUils.CK_GLOBAL_TILE_URL);
        String accessToken = userInfo.getString("access_token");

        if (null == apiUrl || null == fileUrl || null == tileUrl || null == accessToken) {
            return TYPE_FAILED;
        }

        // 1. 组织机构信息
        String syncOrganUrl = apiUrl + "/api/v1/m/sync/offline/" + userNo + "/uorgans";
        String organsRes = OkHttpUtils.builder().addHeader("platform", "android").addHeader("Authorization", "Bearer " + accessToken).url(syncOrganUrl).get().async();
        if (null != organsRes) {
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(organsRes);
            String dataStr = jsonObject.getString("data");
            if (null != dataStr && !"".equals(dataStr)) {
                List<CorporationDO> corporationDos = JSONArray.parseArray(dataStr, CorporationDO.class);
                for (CorporationDO corporationDo : corporationDos) {
                    CorporationService.getInstance().deleteByTenantOrgan(corporationDo.getTenantNo(), corporationDo.getOrganNo());
                    CorporationService.getInstance().saveAll(corporationDo);
                }

            }
        }

        android.util.Log.i("FlygoData: ", "组织机构信息离线完成");
        // 2. 离线故障数据
        String syncDefectUrl = apiUrl + "/api/v1/m/sync/offline/" + organNo + "/defects";
        if(!TextUtils.isEmpty(patrolTimeStr)){
            syncDefectUrl = syncDefectUrl.concat("?patrolTimeStr=").concat(patrolTimeStr);
        }
        String defectsRes = OkHttpUtils.builder().addHeader("platform", "android").addHeader("Authorization", "Bearer " + accessToken).url(syncDefectUrl).get().async();
        List<DefectDO> defectDos = null;
        if (null != defectsRes) {

//            RestResp<List<DefectDO>> restResp = JsonUtils.parseJson2J(defectsRes, new TypeReference<RestResp<List<DefectDO>>>() {
//            });
            RestResp<List<DefectDO>> restResp = JacksonUtils.fromJson2J(defectsRes, new com.fasterxml.jackson.core.type.TypeReference<RestResp<List<DefectDO>>>() {
            });

            if (null != restResp && null != restResp.data && restResp.data.size() > 0) {
                defectDos = restResp.data;
//                DefectService.getInstance().deleteByTenantOrgan(defectDos.get(0).getTenantNo(), organNo);
                DefectService.getInstance().deleteByParams(defectDos.get(0).getTenantNo(), organNo, null, patrolTimeStr, null, null);
                DefectService.getInstance().saveAll(defectDos);
            }
            /*com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(defectsRes);
            String dataStr = jsonObject.getString("data");
            if (null != dataStr && !"".equals(dataStr)) {
                defectDos = JSONArray.parseArray(dataStr, DefectDO.class);

                DefectService.getInstance().deleteByTenantOrgan(defectDos.get(0).getTenantNo(), organNo);
                DefectService.getInstance().saveAll(defectDos);

            }*/
        }

        android.util.Log.i("FlygoData: ", "故障数据信息离线完成");
        // 3. 离线故障自拍图片信息
        String syncDefectInfraredImgUrl = apiUrl + "/sync/offline/" + organNo + "/defect/infrared/imgs";
        if(!TextUtils.isEmpty(patrolTimeStr)){
            syncDefectInfraredImgUrl = syncDefectInfraredImgUrl.concat("?patrolTimeStr=").concat(patrolTimeStr);
        }
        String defectInfraredImgRes = OkHttpUtils.builder().addHeader("platform", "android").addHeader("Authorization", "Bearer " + accessToken).url(syncDefectInfraredImgUrl).get().async();
        List<InfraredImageDO> infraredImageDos = null;
        if (null != defectsRes) {
//            RestResp<List<InfraredImageDO>> restResp = JsonUtils.parseJson2J(defectInfraredImgRes, new TypeReference<RestResp<List<InfraredImageDO>>>() {
//            });
            RestResp<List<InfraredImageDO>> restResp = JacksonUtils.fromJson2J(defectInfraredImgRes, new com.fasterxml.jackson.core.type.TypeReference<RestResp<List<InfraredImageDO>>>() {
            });
            if (null != restResp && null != restResp.data && restResp.data.size() > 0) {
                infraredImageDos = restResp.data;
                InfraredImageService.getInstance().deleteByTenantOrgan(defectDos.get(0).getTenantNo(), organNo);
                InfraredImageService.getInstance().saveAll(infraredImageDos);

            }
            /*com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(defectInfraredImgRes);
            String dataStr = jsonObject.getString("data");
            if (null != dataStr && !"".equals(dataStr)) {
                infraredImageDos = JSONArray.parseArray(dataStr, InfraredImageDO.class);

                InfraredImageService.getInstance().deleteByTenantOrgan(defectDos.get(0).getTenantNo(), organNo);
                InfraredImageService.getInstance().saveAll(infraredImageDos);

            }*/
        }

        android.util.Log.i("FlygoData: ", "故障自拍图片离线完成");
//        NativeJSUtils.writeString2File("defect_" + organNo + ".txt", defectsRes);
        int progress = 5;
        publishProgress(progress);
        // 3. 离线矢量数据
        String syncDeviceUrl = apiUrl + "/api/v1/m/sync/offline/" + organNo + "/devices";
        String devicesRes = OkHttpUtils.builder().addHeader("platform", "android").addHeader("Authorization", "Bearer " + accessToken).url(syncDeviceUrl).get().async();
        if (null != devicesRes) {
//            long start = System.currentTimeMillis();
//            RestResp<List<PvDeviceInfoDO>> restResp1 = JsonUtils.parseJson2J(devicesRes, new TypeReference<RestResp<List<PvDeviceInfoDO>>>() {});
//            long p1 = System.currentTimeMillis();
//            android.util.Log.e("反序列化时间fastjson===============>", "" + (p1 - start));
            RestResp<List<PvDeviceInfoDO>> restResp = JacksonUtils.fromJson2J(devicesRes, new com.fasterxml.jackson.core.type.TypeReference<RestResp<List<PvDeviceInfoDO>>>() {
            });
//            long p2 = System.currentTimeMillis();
//            android.util.Log.e("反序列化时间jackson===============>", "" + (p2 - p1));
//            RestResp<List<PvDeviceInfoDO>> restResp3 = GsonUtils.fromJson2J(devicesRes, new TypeToken<RestResp<List<PvDeviceInfoDO>>>() {
//            });
//            long p3 = System.currentTimeMillis();
//            android.util.Log.e("反序列化时间gson===============>", "" + (p3 - p2));
            if (null != restResp && null != restResp.data && restResp.data.size() > 0) {
                List<PvDeviceInfoDO> deviceInfoDos = restResp.data;
                PvDeviceInfoService.getInstance().deleteByTenantOrgan(deviceInfoDos.get(0).getTenantNo(), organNo);
                PvDeviceInfoService.getInstance().saveAll(deviceInfoDos);
            }
            //                com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(devicesRes);
//                String dataStr = jsonObject.getString("data");
//                if (null != dataStr && !"".equals(dataStr)) {
//                    List<PvDeviceInfoDO> deviceInfoDos = JSONArray.parseArray(dataStr, PvDeviceInfoDO.class);
//                    PvDeviceInfoService.getInstance().deleteByTenantOrgan(deviceInfoDos.get(0).getTenantNo(), organNo);
//                    PvDeviceInfoService.getInstance().saveAll(deviceInfoDos);
//                }

        }

        android.util.Log.i("FlygoData: ", "矢量数据离线完成");
//        NativeJSUtils.writeString2File("device_" + organNo + ".txt", devicesRes);
        if ((null == offlineImageSet || !offlineImageSet) && (null == offlineTiles || !offlineTiles)) {
            progress = 100;
            publishProgress(progress);
            return TYPE_SUCCESS;
        } else {
            progress = 10;
            publishProgress(progress);
        }
        // 4. 离线故障图片
        if (null != offlineImageSet && offlineImageSet) {
            if (null != defectDos && defectDos.size() > 0) {
                int cnt = 1;
                int step = defectDos.size() / 40;
                step = (step == 0 ? 1 : step);
                for (DefectDO defectDo : defectDos) {
                    String faultImgs = defectDo.getFaultImg();
                    if (null == faultImgs || "".equals(faultImgs.trim())) {
                        cnt++;
                        continue;
                    }
                    String[] faultImgArr = faultImgs.split(",");
                    for (String faultImg : faultImgArr) {
                        faultImg = faultImg.replaceAll("/data/var/flygo/data/", "");
                        progress = 10 + cnt / step;
                        downloadFaultImg(fileUrl.concat(faultImg), progress);
                    }

                    cnt++;
                    publishProgress(progress);
                }
            }
            if (null != infraredImageDos && infraredImageDos.size() > 0) {

                for (InfraredImageDO infraredImageDO : infraredImageDos) {
                    String infraredImg = infraredImageDO.getFileUrl();
                    if (null == infraredImg || "".equals(infraredImg.trim())) {
                        continue;
                    }
                    infraredImg = infraredImg.replaceAll("/data/var/flygo/data/", "");
                    downloadFaultImg(fileUrl.concat(infraredImg), progress);
                }
            }
        }
        if (null == offlineTiles || !offlineTiles) {
            progress = 100;
            publishProgress(progress);
            return TYPE_SUCCESS;
        } else {
            progress = 50;
            publishProgress(progress);
        }

        // 5. 离线瓦片图
        if (null != offlineTiles && offlineTiles) {
            String syncTileTxtUrl = apiUrl + "/api/v1/m/sync/offline/" + organNo + "/tiles";

            String filePath = OkHttpUtils.builder().addHeader("platform", "android").addHeader("Authorization", "Bearer " + accessToken).url(syncTileTxtUrl).get().asyncFile("/tile", "tiles_" + organNo + ".txt");
            if (!TextUtils.isEmpty(filePath)) {
                String fileContent = NativeJSUtils.readFile2String(filePath);
                Map<String, Object> map = JSON.parseObject(fileContent, Map.class);
                if(!map.containsKey("code")){
                    Set<String> keySet = map.keySet();
                    int cnt = 1;
                    int step = keySet.size() / 50;
                    step = (step == 0 ? 1 : step);
                    for (String key : keySet) {
                        String[] zxyArr = key.split("__");
                        progress = 50 + cnt / step;
                        downloadTileImg(tileUrl.concat("/").concat(zxyArr[0]).concat("/").concat(zxyArr[1]).concat("/").concat(zxyArr[2]), progress);
                        cnt++;
                        publishProgress(progress);
                    }
                }
            }
        }
        publishProgress(100);
        return TYPE_SUCCESS;
    }
}
